﻿using System;
using System.Linq;
using ClusterAware;
using System.Management;
using ClusterAwareProperties;
using ClusterAwareAdmin.Properties;

namespace ClusterAwareAdmin
{
    /// <summary>
    /// Admin Group Methods Class
    /// </summary>
    public class GroupAdmin : GroupMethods
    {

        #region private properties

        private readonly ClusterManagerAdmin _managerclass;

        #endregion

        #region ctor

        /// <summary>
        /// Create Class GroupMethodsAdmin
        /// </summary>
        /// <param name="managerclass">Instance of ClusterManager class</param>
        public GroupAdmin(ClusterManagerAdmin managerclass)
            : base(managerclass.ManagerInstance)
        {
            _managerclass = managerclass;
        }

        #endregion

        #region public methods

        /// <summary>
        /// Create a new Group
        /// </summary>
        /// <param name="groupName">new group name</param>
        ///<exception cref="ClusterManagerException">
        /// this method throws exception for the following conditions:
        /// Not Connected, 
        /// Parameter group name is empty, 
        /// Group not exists, 
        /// Failed WMI method execution
        /// </exception>
        public void Create(string groupName)
        {
            if (!_managerclass.IsConnected)
            {
                throw new ClusterManagerException(Resources.Error_NotConnected);
            }
            if (string.IsNullOrEmpty(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "groupName"));
            }
            try
            {
                var path = new ManagementPath("MSCluster_ResourceGroup");
                using (var classInstance = new ManagementClass(_managerclass.ScopeManager, path, new ObjectGetOptions()))
                {
                    using (var inParams = classInstance.GetMethodParameters("CreateGroup"))
                    {
                        inParams["GroupName"] = groupName;
                        classInstance.InvokeMethod("CreateGroup", inParams, null);
                        if (_managerclass.CacheInstances)
                        {
                            _managerclass.Refresh(RefreshOption.Groups,groupName);
                        }
                    }
                }
            }
            catch (ManagementException ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Create", ex.Message), ex);
            }
            catch (Exception ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Create", ex.Message), ex);
            }
        }

        /// <summary>
        /// Delete a group
        /// </summary>
        /// <param name="groupName">Group name</param>
        /// <remarks>
        /// If property CacheInstances of CusterManager is true all resoures in cache are refreshed
        /// </remarks>
        ///<exception cref="ClusterManagerException">
        /// this method throws exception for the following conditions:
        /// Not Connected, 
        /// Parameter group name is empty, 
        /// Group not exists, 
        /// Failed WMI method execution
        /// </exception>
        public void Delete(string groupName)
        {
            if (!_managerclass.IsConnected)
            {
                throw new ClusterManagerException(Resources.Error_NotConnected);
            }
            if (string.IsNullOrEmpty(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "groupName"));
            }
            if (!_managerclass.Groups.ExistGroup(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamNotExist, "Group", groupName));
            }
            try
            {
                var group = _managerclass.Groups.GetGroup(groupName);
                var resdel = _managerclass.Groups.GetResources(groupName).Select(r => r.Name);
                using (var inParams = group.Instance.GetMethodParameters("DeleteGroup"))
                {
                    group.Instance.InvokeMethod("DeleteGroup", inParams, null);
                    if (_managerclass.CacheInstances)
                    {
                        _managerclass.GroupInstances.Remove(groupName);
                        foreach (var res in resdel)
                        {
                            _managerclass.ResourceInstances.Remove(res);
                        }
                    }
                }
            }
            catch (ManagementException ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Delete", ex.Message), ex);
            }
            catch (Exception ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Delete", ex.Message), ex);
            }
        }

        /// <summary>
        /// Rename a group
        /// </summary>
        /// <param name="groupName">Current group name</param>
        /// <param name="newgroupName">New group name</param>
        ///<exception cref="ClusterManagerException">
        /// this method throws exception for the following conditions:
        /// Not Connected, 
        /// Parameter group name is empty, 
        /// Group not exists, 
        /// Parameter new group name is empty, 
        /// New Group exists, 
        /// Failed WMI method execution
        /// </exception>
        public void Rename(string groupName, string newgroupName)
        {
            if (!_managerclass.IsConnected)
            {
                throw new ClusterManagerException(Resources.Error_NotConnected);
            }
            if (string.IsNullOrEmpty(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "groupName"));
            }
            if (string.IsNullOrEmpty(newgroupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "newgroupName"));
            }
            if (!_managerclass.Groups.ExistGroup(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamNotExist, "Group", groupName));
            }
            if (_managerclass.Groups.ExistGroup(newgroupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_AlreadyExist, "Group", newgroupName));
            }
            try
            {
                var group = _managerclass.Groups.GetGroup(groupName);
                using (var inParams = group.Instance.GetMethodParameters("Rename"))
                {
                    inParams["newName"] = newgroupName;
                    group.Instance.InvokeMethod("Rename", inParams, null);
                    if (_managerclass.CacheInstances)
                    {
                        _managerclass.GroupInstances.Remove(groupName);
                        _managerclass.Refresh(RefreshOption.Groups,newgroupName);
                }
                }
            }
            catch (ManagementException ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Rename", ex.Message), ex);
            }
            catch (Exception ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Rename", ex.Message), ex);
            }
        }

        /// <summary>
        /// Destroys the cluster group and any resources in this group.
        /// </summary>
        /// <param name="groupName">Group name</param>
        /// <remarks>
        /// If property CacheInstances of CusterManager is true all resoures in cache are refreshed
        /// </remarks>
        ///<exception cref="ClusterManagerException">
        /// this method throws exception for the following conditions:
        /// Operation System before Windows Server 2008,
        /// Not Connected, 
        /// Parameter group name is empty, 
        /// Group not exists, 
        /// Failed WMI method execution
        /// </exception>
        public void Destroy(string groupName)
        {
            if (!_managerclass.IsConnected)
            {
                throw new ClusterManagerException(Resources.Error_NotConnected);
            }
            if (_managerclass.OperationSystem == WindowsOperationSystem.Windows2003 || _managerclass.OperationSystem == WindowsOperationSystem.Windows2003R2)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_SystemNotSuportMethod, _managerclass.OperationSystem, "Destroy"));
            }
            if (string.IsNullOrEmpty(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "groupName"));
            }
            if (!_managerclass.Groups.ExistGroup(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamNotExist, "Group", groupName));
            }
            try
            {
                var group = _managerclass.Groups.GetGroup(groupName);
                var resdel = _managerclass.Groups.GetResources(groupName).Select(r => r.Name);
                using (var inParams = group.Instance.GetMethodParameters("DestroyGroup"))
                {
                    group.Instance.InvokeMethod("DestroyGroup", inParams, null);
                    if (_managerclass.CacheInstances)
                    {
                        if (_managerclass.CacheInstances)
                        {
                            _managerclass.GroupInstances.Remove(groupName);
                            foreach (var res in resdel)
                            {
                                _managerclass.ResourceInstances.Remove(res);
                            }
                        }
                    }
                }

            }
            catch (ManagementException ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Destroy", ex.Message), ex);
            }
            catch (Exception ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.Destroy", ex.Message), ex);
            }
        }

        /// <summary>
        /// Set Group Type 
        /// </summary>
        /// <param name="groupName">Group Name</param>
        /// <param name="newtype">New type of group</param>
        /// <remarks>
        /// If property CacheInstances of CusterManager is true all resoures in cache are refreshed
        /// </remarks>
        ///<exception cref="ClusterManagerException">
        /// this method throws exception for the following conditions:
        /// Operation System before Windows Server 2008,
        /// Not Connected, 
        /// Parameter group name is empty, 
        /// Group not exists, 
        /// Failed WMI method execution
        /// </exception>
        public void SetType(string groupName, GroupType newtype)
        {
            if (!_managerclass.IsConnected)
            {
                throw new ClusterManagerException(Resources.Error_NotConnected);
            }
            if (_managerclass.OperationSystem == WindowsOperationSystem.Windows2003 || _managerclass.OperationSystem == WindowsOperationSystem.Windows2003R2)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_SystemNotSuportMethod, _managerclass.OperationSystem, "SetType"));
            }
            if (string.IsNullOrEmpty(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "groupName"));
            }
            if (!_managerclass.Groups.ExistGroup(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamNotExist, "Group", groupName));
            }
            try
            {
                var group = _managerclass.Groups.GetGroup(groupName);
                using (var inParams = group.Instance.GetMethodParameters("SetGroupType"))
                {
                    inParams["GroupType"] = UInt32.Parse(((int)newtype).ToString());
                    group.Instance.InvokeMethod("SetGroupType", inParams, null);
                    if (_managerclass.CacheInstances)
                    {
                        _managerclass.Refresh(RefreshOption.Groups, groupName);
                    }
                }
            }
            catch (ManagementException ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.SetType", ex.Message), ex);
            }
            catch (Exception ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.SetType", ex.Message), ex);
            }
        }

        ///<summary>
        /// Sets the preferred owner list for this resource group.
        ///</summary>
        ///<param name="groupName">Group Name</param>
        ///<param name="nodes">One or more node names (in order of preference if multiple) that can be owners of this resource group.</param>
        ///<exception cref="ClusterManagerException">
        /// this method throws exception for the following conditions:
        /// Operation System before Windows Server 2008,
        /// Not Connected, 
        /// Group name empty or nor exists
        /// Failed WMI method execution
        /// </exception>
        public void SetPreferredOwners(string groupName, string[] nodes)
        {
            if (!_managerclass.IsConnected)
            {
                throw new ClusterManagerException(Resources.Error_NotConnected);
            }
            if (_managerclass.OperationSystem == WindowsOperationSystem.Windows2003 || _managerclass.OperationSystem == WindowsOperationSystem.Windows2003R2)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_SystemNotSuportMethod, _managerclass.OperationSystem, "SetPreferredOwners"));
            }
            if (string.IsNullOrEmpty(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamEmpty, "groupName"));
            }
            if (!_managerclass.Groups.ExistGroup(groupName))
            {
                throw new ClusterManagerException(string.Format(Resources.Error_ParamNotExist, "Group", groupName));
            }
            try
            {
                var group = _managerclass.Groups.GetGroup(groupName);
                using (var inParams = group.Instance.GetMethodParameters("SetPreferredOwners"))
                {
                    inParams["NodeNames"] = nodes;
                    group.Instance.InvokeMethod("SetPreferredOwners", inParams, null);
                    if (_managerclass.CacheInstances)
                    {
                        _managerclass.Refresh(RefreshOption.Groups, groupName);
                    }
                }
            }
            catch (ManagementException ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.SetPreferredOwners", ex.Message), ex);
            }
            catch (Exception ex)
            {
                throw new ClusterManagerException(string.Format(Resources.Error_MethodExecute, "Groups.SetPreferredOwners", ex.Message), ex);
            }
        }

        #endregion

    }
}
